home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / C / GCC / V2-4-5 / GPPLIBSR00 / cc / streambuf < prev    next >
Text File  |  1993-12-08  |  15KB  |  674 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1991, 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #define _STREAM_COMPAT
  19. #ifdef __GNUG__
  20. #pragma implementation "streambuf.h"
  21. #endif
  22.  
  23. #include "ioprivate.h"
  24. extern "C"
  25.   {
  26.   #include <string.h>
  27.   }
  28.  
  29.  
  30. void streambuf::_un_link()
  31. {
  32.     if (_flags & _S_LINKED) {
  33.     streambuf **f;
  34.     for (f = &_list_all; *f != NULL; f = &(*f)->xchain()) {
  35.         if (*f == this) {
  36.         *f = xchain();
  37.         break;
  38.         }
  39.     }
  40.     _flags &= ~_S_LINKED;
  41.     }
  42. }
  43.  
  44. void streambuf::_link_in()
  45. {
  46.     if ((_flags & _S_LINKED) == 0) {
  47.     _flags |= _S_LINKED;
  48.     xchain() = _list_all;
  49.     _list_all = this;
  50.     }
  51. }
  52.  
  53. // Return minimum _pos markers
  54. // Assumes the current get area is the main get area.
  55. int streambuf::_least_marker()
  56. {
  57.     int least_so_far = _egptr - _eback;
  58.     for (register streammarker *mark = _markers;
  59.      mark != NULL; mark = mark->_next)
  60.     if (mark->_pos < least_so_far)
  61.         least_so_far = mark->_pos;
  62.     return least_so_far;
  63. }
  64.  
  65. // Switch current get area from backup buffer to (start of) main get area.
  66.  
  67. void streambuf::switch_to_main_get_area()
  68. {
  69.     char *tmp;
  70.     _flags &= ~_S_IN_BACKUP;
  71.     // Swap _egptr and _other_egptr.
  72.     tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp;
  73.     // Swap _eback and _other_gbase.    
  74.     tmp= _eback; _eback = _other_gbase; _other_gbase = tmp;
  75.     _gptr = _eback;
  76. }
  77.  
  78. // Switch current get area from main get area to (end of) backup area.
  79.  
  80. void streambuf::switch_to_backup_area()
  81. {
  82.     char *tmp;
  83.     _flags |= _S_IN_BACKUP;
  84.     // Swap _egptr and _other_egptr.
  85.     tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp;
  86.     // Swap _gbase and _other_gbase.    
  87.     tmp = _eback; _eback = _other_gbase; _other_gbase = tmp;
  88.     _gptr = _egptr;
  89. }
  90.  
  91. int streambuf::switch_to_get_mode()
  92. {
  93.     if (_pptr > _pbase)
  94.     if (overflow(EOF) == EOF)
  95.         return EOF;
  96.     if (in_backup()) {
  97.     _eback = _aux_limit;
  98.     }
  99.     else {
  100.     _eback = _base;
  101.     if (_pptr > _egptr)
  102.         _egptr = _pptr;
  103.     }
  104.     _gptr = _pptr;
  105.  
  106.     setp(_gptr, _gptr);
  107.  
  108.     _flags &= ~_S_CURRENTLY_PUTTING;
  109.     return 0;
  110. }
  111.  
  112. void streambuf::free_backup_area()
  113. {
  114.     if (in_backup())
  115.     switch_to_main_get_area();  // Just in case.
  116.     delete [] _other_gbase;
  117.     _other_gbase = NULL;
  118.     _other_egptr = NULL;
  119.     _aux_limit = NULL;
  120. }
  121.  
  122. #if 0
  123. int streambuf::switch_to_put_mode()
  124. {
  125.     _pbase = _gptr;
  126.     _pptr = _gptr;
  127.     _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered?
  128.  
  129.     _gptr = _egptr;
  130.     _eback = _egptr;
  131.  
  132.     _flags |= _S_CURRENTLY_PUTTING;
  133.     return 0;
  134. }
  135. #endif
  136.  
  137. #ifdef _G_FRIEND_BUG
  138. int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); }
  139. int __UNDERFLOW(register streambuf *sb)
  140. #else
  141. int __underflow(register streambuf *sb)
  142. #endif
  143. {
  144.     if (sb->put_mode())
  145.         if (sb->switch_to_get_mode() == EOF) return EOF;
  146.     if (sb->_gptr < sb->_egptr)
  147.     return *(unsigned char*)sb->_gptr;
  148.     if (sb->in_backup()) {
  149.     sb->switch_to_main_get_area();
  150.     if (sb->_gptr < sb->_egptr)
  151.         return *sb->_gptr;
  152.     }
  153.     if (sb->have_markers()) {
  154.     // Append [_gbase.._egptr] to backup area.
  155.     int least_mark = sb->_least_marker();
  156.     // needed_size is how much space we need in the backup area.
  157.     int needed_size = (sb->_egptr - sb->_eback) - least_mark;
  158.     int current_Bsize = sb->_other_egptr - sb->_other_gbase;
  159.     int avail; // Extra space available for future expansion.
  160.     if (needed_size > current_Bsize) {
  161.         avail = 0; // 100 ?? FIXME
  162.         char *new_buffer = new char[avail+needed_size];
  163.         if (least_mark < 0) {
  164.         memcpy(new_buffer + avail,
  165.                sb->_other_egptr + least_mark,
  166.                -least_mark);
  167.         memcpy(new_buffer +avail - least_mark,
  168.                sb->_eback,
  169.                sb->_egptr - sb->_eback);
  170.         }
  171.         else
  172.         memcpy(new_buffer + avail,
  173.                sb->_eback + least_mark,
  174.                needed_size);
  175.         delete [] sb->_other_gbase;
  176.         sb->_other_gbase = new_buffer;
  177.         sb->_other_egptr = new_buffer + avail + needed_size;
  178.     }
  179.     else {
  180.         avail = current_Bsize - needed_size;
  181.         if (least_mark < 0) {
  182.         memmove(sb->_other_gbase + avail,
  183.             sb->_other_egptr + least_mark,
  184.             -least_mark);
  185.         memcpy(sb->_other_gbase + avail - least_mark,
  186.                sb->_eback,
  187.                sb->_egptr - sb->_eback);
  188.         }
  189.         else if (needed_size > 0)
  190.         memcpy(sb->_other_gbase + avail,
  191.                sb->_eback + least_mark,
  192.                needed_size);
  193.     }
  194.     // FIXME: Dubious arithmetic if pointers are NULL
  195.     sb->_aux_limit = sb->_other_gbase + avail;
  196.     // Adjust all the streammarkers.
  197.     int delta = sb->_egptr - sb->_eback;
  198.     for (register streammarker *mark = sb->_markers;
  199.          mark != NULL; mark = mark->_next)
  200.         mark->_pos -= delta;
  201.     }
  202.     else if (sb->have_backup())
  203.     sb->free_backup_area();
  204.     return sb->underflow();
  205. }
  206.  
  207. #ifdef _G_FRIEND_BUG
  208. int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); }
  209. int __OVERFLOW(register streambuf *sb, int c)
  210. #else
  211. int __overflow(streambuf* sb, int c)
  212. #endif
  213. {
  214.     return sb->overflow(c);
  215. }
  216.  
  217. int streambuf::xsputn(register const char* s, int n)
  218. {
  219.     if (n <= 0)
  220.     return 0;
  221.     register int more = n;
  222.     for (;;) {
  223.     int count = _epptr - _pptr; // Space available.
  224.     if (count > 0) {
  225.         if (count > more)
  226.         count = more;
  227.         if (count > 20) {
  228.         memcpy(_pptr, s, count);
  229.         s += count;
  230.         _pptr += count;
  231.         }
  232.         else if (count <= 0)
  233.         count = 0;
  234.         else {
  235.         register char *p = _pptr;
  236.         for (register int i = count; --i >= 0; ) *p++ = *s++;
  237.         _pptr = p;
  238.         }
  239.         more -= count;
  240.     }
  241.     if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF)
  242.         break;
  243.     more--;
  244.     }
  245.     return n - more;
  246. }
  247.  
  248. int streambuf::padn(char pad, int count)
  249. {
  250. #define PADSIZE 16
  251.     static char const blanks[PADSIZE] =
  252.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  253.     static char const zeroes[PADSIZE] =
  254.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  255.     char padbuf[PADSIZE];
  256.     const char *padptr;
  257.     register int i;
  258.     
  259.     if (pad == ' ')
  260.     padptr = blanks;
  261.     else if (pad == '0')
  262.     padptr = zeroes;
  263.     else {
  264.     for (i = PADSIZE; --i >= 0; ) padbuf[i] = pad;
  265.     padptr = padbuf;
  266.     }
  267.     for (i = count; i >= PADSIZE; i -= PADSIZE)
  268.     if (sputn(padptr, PADSIZE) != PADSIZE)
  269.         return EOF;
  270.     if (i > 0 && sputn(padptr, i) != i)
  271.     return EOF;
  272.     return pad;
  273. }
  274.  
  275. int streambuf::xsgetn(char* s, int n)
  276. {
  277.     register int more = n;
  278.     for (;;) {
  279.     int count = _egptr - _gptr; // Data available.
  280.     if (count > 0) {
  281.         if (count > more)
  282.         count = more;
  283.         if (count > 20) {
  284.         memcpy(s, _gptr, count);
  285.         s += count;
  286.         _gptr += count;
  287.         }
  288.         else if (count <= 0)
  289.         count = 0;
  290.         else {
  291.         register char *p = _gptr;
  292.         for (register int i = count; --i >= 0; ) *s++ = *p++;
  293.         _gptr = p;
  294.         }
  295.         more -= count;
  296.     }
  297.     if (more == 0 || __underflow(this) == EOF)
  298.         break;
  299.     }
  300.     return n - more;
  301. }
  302.  
  303. int streambuf::ignore(int n)
  304. {
  305.     register int more = n;
  306.     for (;;) {
  307.     int count = _egptr - _gptr; // Data available.
  308.     if (count > 0) {
  309.         if (count > more)
  310.         count = more;
  311.         _gptr += count;
  312.         more -= count;
  313.     }
  314.     if (more == 0 || __underflow(this) == EOF)
  315.         break;
  316.     }
  317.     return n - more;
  318. }
  319.  
  320. int streambuf::sync()
  321. {
  322.     if (gptr() == egptr() && pptr() == pbase())
  323.     return 0;
  324.     return EOF;
  325. }
  326.  
  327. int streambuf::pbackfail(int c)
  328. {
  329.     if (_gptr > _eback)
  330.     _gptr--;
  331.     else if (seekoff(-1, ios::cur, ios::in) == EOF)
  332.     return EOF;
  333.     if (c != EOF && *_gptr != c)
  334.     *_gptr = c;
  335.     return (unsigned char)c;
  336. }
  337.  
  338. streambuf* streambuf::setbuf(char* p, int len)
  339. {
  340.     if (sync() == EOF)
  341.     return NULL;
  342.     if (p == NULL || len == 0) {
  343.     unbuffered(1);
  344.     setb(_shortbuf, _shortbuf+1, 0);
  345.     }
  346.     else {
  347.     unbuffered(0);
  348.     setb(p, p+len, 0);
  349.     }
  350.     setp(0, 0);
  351.     setg(0, 0, 0);
  352.     return this;
  353. }
  354.  
  355. streampos streambuf::seekpos(streampos pos, int mode)
  356. {
  357.     return seekoff(pos, ios::beg, mode);
  358. }
  359.  
  360. void streambuf::setb(char* b, char* eb, int a)
  361. {
  362.     if (_base && !(_flags & _S_USER_BUF))
  363.     FREE_BUF(_base);
  364.     _base = b;
  365.     _ebuf = eb;
  366.     if (a)
  367.     _flags &= ~_S_USER_BUF;
  368.     else
  369.     _flags |= _S_USER_BUF;
  370. }
  371.  
  372. int streambuf::doallocate()
  373. {
  374.     char *buf = ALLOC_BUF(_G_BUFSIZ);
  375.     if (buf == NULL)
  376.     return EOF;
  377.     setb(buf, buf+_G_BUFSIZ, 1);
  378.     return 1;
  379. }
  380.  
  381. void streambuf::doallocbuf()
  382. {
  383.     if (base() || (!unbuffered() && doallocate() != EOF)) return;
  384.     setb(_shortbuf, _shortbuf+1, 0);
  385. }
  386.  
  387. streambuf::streambuf(int flags)
  388. {
  389.   _flags = _IO_MAGIC|flags;
  390.   _base = NULL;
  391.   _ebuf = NULL;
  392.   _eback = NULL;
  393.   _gptr = NULL;
  394.   _egptr = NULL;
  395.   _pbase = NULL;
  396.   _pptr = NULL;
  397.   _epptr = NULL;
  398.   _chain = NULL; // Not necessary.
  399.  
  400.   _other_gbase = NULL;
  401.   _aux_limit = NULL;
  402.   _other_egptr = NULL;
  403.   _markers = NULL;
  404.   _cur_column = 0;
  405. }
  406.  
  407. streambuf::~streambuf()
  408. {
  409.     if (_base && !(_flags & _S_USER_BUF))
  410.     FREE_BUF(_base);
  411.  
  412.     for (register streammarker *mark = _markers;
  413.      mark != NULL; mark = mark->_next)
  414.     mark->_sbuf = NULL;
  415.     
  416. }
  417.  
  418. streampos
  419. streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/)
  420. {
  421.     return EOF;
  422. }
  423.  
  424. int streambuf::sputbackc(char c)
  425. {
  426.     if (_gptr > _eback && (unsigned char)_gptr[-1] == (unsigned char)c) {
  427.     _gptr--;
  428.     return (unsigned char)c;
  429.     }
  430.     return pbackfail(c);
  431. }
  432.  
  433. int streambuf::sungetc()
  434. {
  435.     if (_gptr > _eback) {
  436.     _gptr--;
  437.     return (unsigned char)*_gptr;
  438.     }
  439.     else
  440.     return pbackfail(EOF);
  441. }
  442.  
  443. #if 0 /* Work in progress */
  444. void streambuf::collumn(int c)
  445. {
  446.     if (c == -1)
  447.     _collumn = -1;
  448.     else
  449.     _collumn = c - (_pptr - _pbase);
  450. }
  451. #endif
  452.  
  453.  
  454. int streambuf::get_column()
  455. {
  456.     if (_cur_column) 
  457.     return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
  458.     return -1;
  459. }
  460.  
  461. int streambuf::set_column(int i)
  462. {
  463.     _cur_column = i+1;
  464.     return 0;
  465. }
  466.  
  467. int streambuf::flush_all()
  468. {
  469.     int result = 0;
  470.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  471.     if (sb->overflow(EOF) == EOF)
  472.         result = EOF;
  473.     return result;
  474. }
  475.  
  476. void streambuf::flush_all_linebuffered()
  477. {
  478.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  479.     if (sb->linebuffered())
  480.         sb->overflow(EOF);
  481. }
  482.  
  483. int backupbuf::underflow()
  484. {
  485.     return EOF;
  486. }
  487.  
  488. int backupbuf::overflow(int c)
  489. {
  490.     return EOF;
  491. }
  492.  
  493. streammarker::streammarker(streambuf *sb)
  494. {
  495.     _sbuf = sb;
  496.     if (!(sb->xflags() & _S_IS_BACKUPBUF)) {
  497.     set_streampos(sb->seekoff(0, ios::cur, ios::in));
  498.     _next = 0;
  499.     }
  500.     else {
  501.     if (sb->put_mode())
  502.         sb->switch_to_get_mode();
  503.     if (((backupbuf*)sb)->in_backup())
  504.         set_offset(sb->_gptr - sb->_egptr);
  505.     else
  506.         set_offset(sb->_gptr - sb->_eback);
  507.  
  508.     // Should perhaps sort the chain?
  509.     _next = ((backupbuf*)sb)->_markers;
  510.     ((backupbuf*)sb)->_markers = this;
  511.     }
  512. }
  513.  
  514. streammarker::~streammarker()
  515. {
  516.     if (saving()) {
  517.     // Unlink from sb's chain.
  518.     register streammarker **ptr = &((backupbuf*)_sbuf)->_markers;
  519.     for (; ; ptr = &(*ptr)->_next)
  520.         if (*ptr == NULL)
  521.         break;
  522.         else if (*ptr == this) {
  523.         *ptr = _next;
  524.         return;
  525.         }
  526.     }
  527. #if 0
  528.     if _sbuf has a backup area that is no longer needed, should we delete
  529.     it now, or wait until underflow()?
  530. #endif
  531. }
  532.  
  533. #define BAD_DELTA EOF
  534.  
  535. int streammarker::delta(streammarker& other_mark)
  536. {
  537.     if (_sbuf != other_mark._sbuf)
  538.     return BAD_DELTA;
  539.     if (saving() && other_mark.saving())
  540.     return _pos - other_mark._pos;
  541.     else if (!saving() && !other_mark.saving())
  542.     return _spos - other_mark._spos;
  543.     else
  544.     return BAD_DELTA;
  545. }
  546.  
  547. int streammarker::delta()
  548. {
  549.     if (_sbuf == NULL)
  550.     return BAD_DELTA;
  551.     if (saving()) {
  552.     int cur_pos;
  553.     if (_sbuf->in_backup())
  554.         cur_pos = _sbuf->_gptr - _sbuf->_egptr;
  555.     else
  556.         cur_pos = _sbuf->_gptr - _sbuf->_eback;
  557.     return _pos - cur_pos;
  558.     }
  559.     else {
  560.     if (_spos == EOF)
  561.         return BAD_DELTA;
  562.     int cur_pos = _sbuf->seekoff(0, ios::cur);
  563.     if (cur_pos == EOF)
  564.         return BAD_DELTA;
  565.     return _pos - cur_pos;
  566.     }
  567. }
  568.  
  569. int streambuf::seekmark(streammarker& mark, int delta /* = 0 */)
  570. {
  571.     if (mark._sbuf != this)
  572.     return EOF;
  573.     if (!mark.saving()) {
  574.     return seekpos(mark._spos, ios::in);
  575.     }
  576.     else if (mark._pos >= 0) {
  577.     if (in_backup())
  578.         switch_to_main_get_area();
  579.     _gptr = _eback + mark._pos;
  580.     }
  581.     else {
  582.     if (!in_backup())
  583.         switch_to_backup_area();
  584.     _gptr = _egptr + mark._pos;
  585.     }
  586.     return 0;
  587. }
  588.  
  589. void streambuf::unsave_markers()
  590. {
  591.     register streammarker *mark =_markers;
  592.     if (_markers) {
  593.     streampos offset = seekoff(0, ios::cur, ios::in);
  594.     if (offset != EOF) {
  595.         offset += eGptr() - Gbase();
  596.         for ( ; mark != NULL; mark = mark->_next)
  597.         mark->set_streampos(mark->_pos + offset);
  598.     }
  599.     else {
  600.         for ( ; mark != NULL; mark = mark->_next)
  601.         mark->set_streampos(EOF);
  602.     }
  603.     _markers = 0;
  604.     }
  605.  
  606.     free_backup_area();
  607. }
  608.  
  609. int backupbuf::pbackfail(int c)
  610. {
  611.   if (_gptr <= _eback) {
  612.     // Need to handle a filebuf in write mode (switch to read mode).  FIXME!
  613.  
  614.     if (have_backup() && !in_backup()) {
  615.     switch_to_backup_area();
  616.     }
  617.     if (!have_backup()) {
  618.     // No backup buffer: allocate one.
  619.     // Use short buffer, if unused? (probably not)  FIXME 
  620.     int backup_size = 128;
  621.     _other_gbase = new char [backup_size];
  622.     _other_egptr = _other_gbase + backup_size;
  623.     _aux_limit = _other_egptr;
  624.     switch_to_backup_area();
  625.     }
  626.     else if (gptr() <= eback()) {
  627.     // Increase size of existing backup buffer.
  628.     size_t new_size;
  629.     size_t old_size = egptr() - eback();
  630.     new_size = 2 * old_size;
  631.     char* new_buf = new char [new_size];
  632.     memcpy(new_buf+(new_size-old_size), eback(), old_size);
  633.     delete [] eback();
  634.     setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size);
  635.     _aux_limit = _gptr;
  636.     }
  637.   }
  638.   _gptr--;
  639.   if (c != EOF && *_gptr != c)
  640.     *_gptr = c;
  641.   return (unsigned char)*_gptr;
  642. }
  643.  
  644. unsigned __adjust_column(unsigned start, const char *line, int count)
  645. {
  646.     register const char *ptr = line + count;
  647.     while (ptr > line)
  648.     if (*--ptr == '\n')
  649.         return line + count - ptr - 1;
  650.     return start + count;
  651. }
  652.  
  653. int ios::readable() { return !(rdbuf()->_flags & _S_NO_READS); }
  654. int ios::writable() { return !(rdbuf()->_flags & _S_NO_WRITES); }
  655. int ios::is_open() { return rdbuf()
  656.              && (rdbuf()->_flags & _S_NO_READS+_S_NO_WRITES)
  657.                  != _S_NO_READS+_S_NO_WRITES; }
  658.  
  659. #if defined(linux)
  660. #define IO_CLEANUP ;
  661. #endif
  662.  
  663. /*#undef IO_CLEANUP*/
  664.  
  665. #ifdef IO_CLEANUP
  666.   IO_CLEANUP
  667. #else
  668. struct __io_defs {
  669.     __io_defs() { }
  670.     ~__io_defs() { streambuf::flush_all(); }
  671. };   
  672. __io_defs io_defs__;
  673. #endif
  674.